package osami.communication;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

import osami.communication.translate.MulticastJoinMessage;
import osami.communication.translate.TranslationException;
import osami.communication.translate.Translator;

/**
 * MCListener listens to Multicast -connection and
 * acts on demand.
 * 
 * @author osami
 *
 */
public class TCPIPMulticastListener implements ConnectionListener
{
	private CommServer iCommServer;
	private MulticastSocket iSocket;
	private Translator iTranslator = null;
	private Thread iListenerThread = null;

	public static final int PORT = 6744;					// 6744 = OSGI
	public static final String MCADDRESS = "224.0.23.187";  // MULTICAST ADDRESS TO LISTEN TO
	public static final int DGRAM_LENGTH = 16;				// SIZE OF DATAGRAM PACKET

	
	/**
	 * Creates a new instance of TCPIPMulticastListener
	 * 
	 * @param aEngine
	 * @param aCommServer
	 * @throws OsamiException
	 */
	
	public TCPIPMulticastListener( Activator aEngine, CommServer aCommServer ) throws OsamiException
	{
		iCommServer = aCommServer;
		
		iTranslator = iCommServer.getTranslator( "json" );
		
		// create and start a thread in which the listener runs
		iListenerThread = new Thread( this );
		iListenerThread.start();
	}
	
	/**
	 * Creates a server socket and starts to listen to incoming connections.
	 * 
	 */
	public void run()
	{
		boolean running = true;
		boolean first = true;
		byte[] b = new byte[DGRAM_LENGTH];
		DatagramPacket incomingDgram = new DatagramPacket( b, b.length );

		
		try
		{
			// create a Listener socket for Multicast
			System.out.println( "MCListener running. Listening to: " + MCADDRESS + " : " + Integer.toString( PORT ) );
			iSocket = new MulticastSocket( PORT );
			
			iSocket.joinGroup( InetAddress.getByName( MCADDRESS ) );
			
			MulticastJoinMessage message = new MulticastJoinMessage( MulticastJoinMessage.ACTION_ADD );

			String strMessage = iTranslator.translate( message );
			
			byte[] messageBytes = strMessage.getBytes();
			DatagramPacket joinDgram = new DatagramPacket( messageBytes, messageBytes.length, InetAddress.getByName( MCADDRESS ), PORT );
			iSocket.send( joinDgram );
		}
		catch( IOException aException )
		{
			aException.printStackTrace();
		}
		catch ( TranslationException aException )
		{
			// TODO Auto-generated catch block
			aException.printStackTrace();
		}

		
		while( running && !iSocket.isClosed() )
		{
			try
			{
				// blocks until a datagram is received
				iSocket.receive( incomingDgram );

				TCPIPAddress remAddress = new TCPIPAddress( incomingDgram.getAddress().toString().substring(1) );
				MulticastJoinMessage message = (MulticastJoinMessage)iTranslator.translate( new String( incomingDgram.getData() ) );
				
				// CHECK FOR RELEVANT INFORMATION IN MULTICAST MESSAGE
				switch( message.getAction() )
				{
				case MulticastJoinMessage.ACTION_ADD:
				{
					if ( first )
					{
						first = false;
					}
					else
					{
						if( !remAddress.equals() )
						{
					    	System.out.println( "MC from: " + remAddress + ", connecting" );
					    	iCommServer.connectTo( remAddress );
						}
						else
						{
							System.out.println( "Will not connect to self" );
						}
					}
				}break;
				case MulticastJoinMessage.ACTION_REMOVE:
				{
					Connection conn = iCommServer.getConnection( remAddress );
					if ( conn != null ) conn.unregister();
				}break;
				default:
				{
					
				}break;
				}

				// reset length field
				incomingDgram.setLength( DGRAM_LENGTH );
			}
			catch( IOException aException )
			{
				System.out.println( "MCListener: could not connect: " + aException.getMessage() );
//				aException.printStackTrace();
			}
			catch ( TranslationException aException )
			{
				aException.printStackTrace();
			}
			catch ( OsamiException aException )
			{
				aException.printStackTrace();
			}
		}
	}

	/**
	 * Closes server socket.
	 * 
	 * @throws IOException
	 */
	public void closeConnection()
	{
		MulticastJoinMessage message = new MulticastJoinMessage( MulticastJoinMessage.ACTION_REMOVE );

		try
		{
			String strMessage = iTranslator.translate( message );
			byte[] b = strMessage.getBytes();
			
			// send leave message
			DatagramPacket joinDgram = new DatagramPacket(b, b.length, InetAddress.getByName(MCADDRESS), PORT );
			iSocket.send( joinDgram );
			
			iSocket.leaveGroup( InetAddress.getByName( MCADDRESS ) );
			
			iListenerThread.interrupt();
		}
		catch ( TranslationException aException )
		{
			// TODO Auto-generated catch block
			aException.printStackTrace();
		}
		catch ( IOException aException )
		{
			// TODO Auto-generated catch block
			aException.printStackTrace();
		}
		
		iSocket.close();
	}
}